/*************************************************************************************************
 * The skeletion multi-tables database for Tokyo Cabinet
 * @Author: Riceball LEE(riceballl@hotmail.com)
 *                                       Copyright (C) 2009 CloudDatabase
 *************************************************************************************************/


#ifndef _TCSKBDB_H                         /* duplication check */
#define _TCSKBDB_H

#if defined(__cplusplus)
#define __TCSKBDB_CLINKAGEBEGIN extern "C" {
#define __TCSKBDB_CLINKAGEEND }
#else
#define __TCSKBDB_CLINKAGEBEGIN
#define __TCSKBDB_CLINKAGEEND
#endif
__TCSKBDB_CLINKAGEBEGIN

#include <tcadb.h>
#include <tctdb.h>
#include <tchdb.h>
#include <tcbdb.h>
#include <tcutil.h>

#define TDBITREINDEX     10000
#define FIELDSEPSTR     "."   //field seperator string
#define FIELDSEPCHAR     '.'  //field seperator char
#define FIELDVALSEPSTR  "\0/" //"\0/"
#define FIELDVALSEPSTRSIZE  sizeof(FIELDVALSEPSTR)
#define KEYSEPSTR       "/"
#define KEYSEPCHAR       '/'
#define DOTSTR           "."
#define DOTCHAR          '.' 
#define IDXCONFIGKEY     "_DB/index/_conf/"             // the prefix of the index config key.
#define IDXCOUNTCONFIGKEY "_DB/index/_conf/count/"             // the prefix of the index config key. _DB/index/_conf/count/[FieldName]
#define REC_COUNTCFGKEY  "_DB/_conf/record/count"       //the config key for all record count 
#define DBVERCFGKEY  "_DB/_conf/ver"           // the DB Data Version No. 
#define IDXKEY           "/"                   // the prefix of the index key.
#define IDXEXTNAME       ".idx"                         // the extension name of the index file.
#define CFGEXTNAME       ".cfg"                         // the extension name of the config file(MUST BE THE SAME LENGTH AS THE INDEX EXT NAME). 
#define MAXKEYLEN        4095
#define MAXCONFIGMMAPSIZE  1024000
#define MAXINDEXMMAPSIZE   10240000

//MUST USE THE TCESUCCESS, TCEINVALID, TCENOREC, TCEKEEP , or fatal error.
//enum {                                   /* enumeration for error codes */
//  TCESUCCESS,                            /* success */
//  TCETHREAD,                             /* threading error */
//  TCEINVALID,                            /* invalid operation */
//  TCENOFILE,                             /* file not found */
//  TCENOPERM,                             /* no permission */
//  TCEMETA,                               /* invalid meta data */
//  TCERHEAD,                              /* invalid record header */
//  TCEOPEN,                               /* open error */
//  TCECLOSE,                              /* close error */
//  TCETRUNC,                              /* trunc error */
//  TCESYNC,                               /* sync error */
//  TCESTAT,                               /* stat error */
//  TCESEEK,                               /* seek error */
//  TCEREAD,                               /* read error */
//  TCEWRITE,                              /* write error */
//  TCEMMAP,                               /* mmap error */
//  TCELOCK,                               /* lock error */
//  TCEUNLINK,                             /* unlink error */
//  TCERENAME,                             /* rename error */
//  TCEMKDIR,                              /* mkdir error */
//  TCERMDIR,                              /* rmdir error */
//  TCEKEEP,                               /* existing record */
//  TCENOREC,                              /* no record found */
//  TCEMISC = 9999                         /* miscellaneous error */
//  TCESKELBDB= 10000,                         /* the SKELBDB custom error */
//  TCEREMOVEINDEX                             /* remove index error */
//};
typedef unsigned short int WORD;
typedef unsigned char BYTE;

typedef struct {
  unsigned char Indexed:1;
  unsigned char Type:7;
} TFieldType;

#define ISFIELDINDEX(aFieldType) \
  ((aFieldType && 0x80) == 0x80)
// (aFiledType >> 7)

enum {                                   // enumeration for field type
  TDBTVOID,                              // 0
  TDBTSTRING,                            // 1
  TDBTINT8,                              // 2
  TDBTINT16,                             // 3
  TDBTINT32,                             // 4
  TDBTINT64,                             // 5
  TDBTUINT8,                             // 6
  TDBTUINT16,                            // 7
  TDBTUINT32,                            // 8
  TDBTUINT64,                            // 9
  TDBTBOOL,                              // 10
  TDBTSINGLE,                            //  single (32bit)
  TDBTDOUBLE,                            //  double (64bit)
  TDBTLDOUBLE,                           //  long double (80bit)
  TDBTDATE,                              // 
  TDBTDATETIME,                          // 
  TDBTTIME                               // 
};

/* callback Put/PutKeep */
typedef bool (*TCADBPUTPROC)(TCADB *aDB, const void *kbuf, int ksiz, const void *vbuf, int vsiz);
typedef bool (*TCBDBPUTPROC)(TCBDB *aDB, const void *kbuf, int ksiz, const void *vbuf, int vsiz);
typedef bool (*TCBDBOUTPROC)(TCBDB *aDB, const void *kbuf, int ksiz);


typedef struct {                        // type of structure for skel bdb database
  void *mmtx;                            /* mutex for method */
  bool Opened;                             /* whether the internal database is opened */
  bool Writable;                            /* whether to be writable */
  TCBDB *IndexDB;                       // indexes to store
  TCHDB *ConfigDB;                      // DB and index configuration (Hash DB) to store
  TCBDB *DB;                           // Main Data DB to store
  BDBCUR *Cursor;                      /* the cursor of B+ tree DB */
  bool InTransaction;                  /* whether in the transaction */
  TCMAP *IndexCache;                   /* internal index cache object */

#if defined(__cplusplus)
  void* tcDBNew(void);
  void tcDBFree(void);
  bool tcDBOpen(const char *aName);
  bool tcDBClose(void);
  bool tcDBReplace(const char *kbuf, int ksiz, const char *vbuf, int vsiz);
  bool tcDBInsert(const char *kbuf, int ksiz, const char *vbuf, int vsiz);
  bool tcDBUpdateCat(const char *kbuf, int ksiz, const char *vbuf, int vsiz);
  bool tcDBDelete(const char *kbuf, int ksiz);
  void* tcDBGet(const char *aKey, int aKeySize, int *aValueSize);
  int tcDBGetValueSize(const char *aKey, int aKeySize);
  bool tcDBIterInit(void);
  void* tcDBIterNext(int *aSize);
  TCLIST* tcDBGetMatchedKeys(const char *aKey, int aKeySize, int aMaxCount);
  int tcDBAddInt(const char *aKey, int aKeySize, int aNumber);
  double tcDBAddDouble(const char *aKey, int aKeySize, double aNumber);
  bool tcDBSync(void);
  bool tcDBOptimize(const char *aParams);
  bool tcDBClear(void);
  bool tcDBCopy(const char *aPath);
  bool tcDBTransBegin(void);
  bool tcDBTransCommit(void);
  bool tcDBTransAbort(void);
  const char* tcDBPath(void);
  uint64_t tcDBGetRecordNum(void);
  uint64_t tcDBSize(void);
  TCLIST* tcDBExecCmd(const char *name, const TCLIST *args);
  bool tcDBReplaceProc(const void *aKey, int aKeySize, const void *aValue, int aValueSize,
                              TCPDPROC aProc, void *aProcParams);
  bool tcDBForEach(TCITER aIterProc, void *aIterParams);
#endif
} TBTreeDatabase;

typedef struct {                         /* type of structure for a condition */
  char *ColumnName;                      /* column name */
  int ColumnNameSize;                    /* size of the column name */
  int op;                                /* operation type */
  bool sign;                             /* positive sign */
  bool noidx;                            /* no index flag(do not use index) */
  char *expr;                            /* operand expression */
  int esiz;                              /* size of the operand expression */
  void *regex;                           /* regular expression object */
  void *ftsunits;                        /* full-text search units */
  int ftsnum;                            /* number of full-text search units */
  bool alive;                            /* alive flag */
  int IndexType;                         /* the index type used only the column is an index and the noidx flag is false. */
} TDBQueryCondition;

typedef struct {                         /* type of structure for a query */
  TBTreeDatabase *DB;                    /* database object */
  TDBQueryCondition *Conditions;         /* condition objects */
  int ConditionCount;                    /* number of conditions */
  char *OrderColumnName;                 /* column name for ordering */
  int OrderType;                         /* type of order */
  int max;                               /* the query max count number of retrieval */
  int skip;                              /* skipping number of retrieval */
  TCXSTR *hint;                          /* hint string */
  int count;                             /* count of corresponding records */
} TDBQuery;


/*************************************************************************************************
 * API
 *************************************************************************************************/
bool tcADBSetSkelDB(TCADB *adb);
//void tcSkelBDBSetEcode(TCBDB *bdb, int ecode, const char *filename, int line, const char *func);
//const char *tcSkelBDBErrMsg(int ecode);

void* tcDBNew(void);
void  tcDBFree(void *aDB);
bool tcDBOpen(void *aDB, const char *aName);
bool tcDBClose(void *aDB);
//add/update a record(key/calue)
bool tcDBReplace(void *aDB, const char *kbuf, int ksiz, const char *vbuf, int vsiz);
//add a record. return false if key exists or other error.
bool tcDBInsert(void *aDB, const char *kbuf, int ksiz, const char *vbuf, int vsiz);
bool tcDBDelete(void *aDB, const char *kbuf, int ksiz);
void *tcDBGet(void *aDB, const char *aKey, int aKeySize, int *aValueSize);
/* Get the size of the value of a record.
 If successful, the return value is the size of the value of the corresponding record, else,
 it is -1. */
int tcDBGetValueSize(void *aDB, const char *aKey, int aKeySize);
/* Initialize the iterator of a reocrd.
 If successful, the return value is true, else, it is false.
 The iterator is used in order to access the key of every record stored in a database. */
bool tcDBIterInit(void *aDB);
/* Get the next key of the iterator of a database object.
 `aDB' specifies the database object.
 `aSize' specifies the pointer to the variable into which the size of the region of the return
 value is assigned.
 If successful, the return value is the pointer to the region of the next key, else, it is
 `NULL'.  `NULL' is returned when no record is to be get out of the iterator.
 Because an additional zero code is appended at the end of the region of the return value, the
 return value can be treated as a character string.  Because the region of the return value is
 allocated with the `malloc' call, it should be released with the `free' call when it is no
 longer in use. */
void *tcDBIterNext(void *aDB, int *aSize);
/* Get forward matched keys in a database object: the first part string is matched with the aKey.
 `aDB' specifies the database object.
 `aKey' specifies the pointer to the region of the prefix.
 `aKeySize' specifies the size of the region of the prefix.
 `aMaxCount' specifies the maximum number of keys to be fetched.  If it is negative, no limit is
 specified.
 The return value is a list object of the corresponding keys.  This function does never fail.
 It returns an empty list even if no key corresponds.
 Because the object of the return value is created with the function `tclistnew', it should be
 deleted with the function `tclistdel' when it is no longer in use.  Note that this function
 may be very slow because every key in the database is scanned. */
TCLIST *tcDBGetMatchedKeys(void *aDB, const char *aKey, int aKeySize, int aMaxCount);
/* Add an integer to a record in a database object.
 `aDB' specifies the abstract database object.
 `aKey' specifies the pointer to the region of the key.
 `aKeySize' specifies the size of the region of the key.
 `aNumber' specifies the additional value.
 If successful, the return value is the summation value, else, it is `INT_MIN'.
 If the corresponding record exists, the value is treated as an integer and is added to.  If no
 record corresponds, a new record of the additional value is stored. */
int tcDBAddInt(void *aDB, const char *aKey, int aKeySize, int aNumber);
double tcDBAddDouble(void *aDB, const char *aKey, int aKeySize, double aNumber);
//append the value to an exists record.
bool tcDBAddString(void *aDB, const char *kbuf, int ksiz, const char *vbuf, int vsiz);
bool tcDBSync(void *aDB);
bool tcDBOptimize(void *aDB, const char *aParams);
bool tcDBClear(void *aDB);
bool tcDBCopy(void *aDB, const char *aPath);
bool tcDBTransBegin(void *aDB);
bool tcDBTransCommit(void *aDB);
bool tcDBTransAbort(void *aDB);
const char *tcDBPath(void *aDB);
//get the record number of the db //exclude the index number and index config.
uint64_t tcDBGetRecordNum(void *aDB);
uint64_t tcDBSize(void *aDB);
//execute the additional commands in misc.
TCLIST *tcDBExecCmd(void *aDB, const char *name, const TCLIST *args);
bool tcDBReplaceProcDup(void *aDB, const void *aKey, int aKeySize, const void *aValue, int aValueSize,
                               TCPDPROC aProc, void *aProcParams);
bool tcDBForEach(void *aDB, TCITER aIterProc, void *aIterParams);
TDBQuery *tcDBQueryCreate(void *aDB);
void tcDBQueryFree(TDBQuery *qry);
bool tcDBQueryProc(TDBQuery *qry, TDBQRYPROC proc, void *op);
//------------------the interface of a DB---END-----
//the old name is tcDBSetEcode
/* Set the error code of a database object. */
/* some critical error will halt progrm, some minro error will report error only.*/
void tcDBRaiseError(void *aDB, int aErrCode, const char *aFilename, int aLine, const char *aFunc);

bool tcDBIndexRemove(void *aDB, const char *aFieldbuf, int aFieldSiz);
/* set an index to a field */
bool tcDBIndexSet(TBTreeDatabase *aDB, const char *aFieldbuf, int aFieldSiz, const char *aOptions, int aOptionsSiz, int aOptionInt);
/* remove the Key with index supports */
bool tcDBDeleteProc(TBTreeDatabase *aDB, const char *kbuf, int ksiz, const TCBDBOUTPROC aOutProc);
/* add/update Key/Structured-Value with index supports */
bool tcDBReplaceProc(TBTreeDatabase *aDB, const char *kbuf, int ksiz, const char *vbuf, int vsiz, const TCBDBPUTPROC aPutProc);
bool tcDBDefrag(TBTreeDatabase *aDB, int64_t aStep);
uint64_t tcDBGetIndexNum(TBTreeDatabase *aDB);
uint64_t tcDBGetConfigNum(TBTreeDatabase *aDB);
int tcDBIndexGetValueSize(void *aDB, const char *aKey, int aKeySize);
int tcDBConfigGetValueSize(void *aDB, const char *aKey, int aKeySize);
TCLIST *tcDBIndexGetMatchedKeys(void *aDB, const char *aKey, int aKeySize, int aMaxCount);

/* 
 Serialize a map object into a byte array.
 the value is always fixed length= aValueSize.
 \(keyNameSize:2bytes)(keyName)(value:aValueSize)
 */
void *tcDictDump2(const TCMAP *map, const BYTE aValueSize, int *aResultSize);
/* Create a map object from a serialized byte array. 
 the value is always fixed length= aValueSize.
 */
TCMAP *tcDictLoad2(const void *ptr, int size, const BYTE aValueSize);
/* 
 Serialize a map object into a byte array.
 \(keyNameSize:16bit)(keyName)\(valueSize:32bit)(value:ValueSize)
 */
void *tcDictDump(const TCMAP *map, int *aResultSize);
/* Create a map object from a serialized byte array. */
TCMAP *tcDictLoad(const void *ptr, int size);

__TCSKBDB_CLINKAGEEND
#endif                                   /* duplication check */


/* END OF FILE */
